package sde.actor.csm;
import java.util.*;

import sde.actor.distribution.*;
import sde.actor.*;

public class Stazione extends IStazione{ 
	private final int CREATED=0, IDLE=1, BUSY=2;
	
	protected String ARRIVO="Arrivo", PARTENZA="Partenza";
	protected static class Departure extends Message{
		private Cliente c;
		public Cliente getCliente(){ return c; }
		public void setCliente( Cliente c ){ this.c=c; }
	}//Departure
	
	private LinkedList<Cliente> buffer = new LinkedList<Cliente>();
	protected Osservatore osservatore;
	private double tempoServizio;
	private Distribution dist;	
	private Stazione prossimaStazione;
	private double ora;
	private Departure departure=new Departure();
	
	public Stazione(){
		become( CREATED );
	}
	
	public void setProssimaStazione( Stazione s ){
		this.prossimaStazione = s;
	}//setProssimaStazione
	
	private double tempoServizio(){
		//calcola durata del servizio
		return dist.nextSample();
	}
	
	@Override
	public void handler( Message m ){
		ora = now();
		switch( currentStatus() ){
		case CREATED:
			if( m instanceof Init ){
				this.dist=((Init)m).dist;
				this.osservatore=((Init)m).osservatore;
				become( IDLE );
			} break;
		case IDLE:
			if( m instanceof Arrival ){
				osservatore.arrivo( ((Arrival)m).getCliente() );
				osservatore.uscitaCoda( ((Arrival)m).getCliente() );
				tempoServizio = tempoServizio();
				departure.setCliente( ((Arrival)m).getCliente() );
				send( departure, tempoServizio+ora );
				pool.addLast( ((Arrival)m) ); //memorizza m per riciclo
				become( BUSY );
			} break;
		case BUSY:
			if( m instanceof Arrival ){
				osservatore.arrivo( ((Arrival)m).getCliente() );
				buffer.add( ((Arrival)m).getCliente() );
				pool.addLast( ((Arrival)m) ); //conserva questo arrival
			}
			else if( m instanceof Departure ){
				osservatore.partenza( ((Departure)m).getCliente() );
				//invia questo cliente alla prossima stazione (se esiste)
				if( prossimaStazione!=null ){
					//trasforma ev in evento di arrivo per la prossima stazione
					if( pool.size()==0 )
						prossimaStazione.send( new Arrival( ((Departure)m).getCliente() ) );
					else{
						Cliente c=((Departure)m).getCliente();
						Arrival a=pool.removeFirst();
						a.setCliente(c);
						prossimaStazione.send( a );
					}
				}	
				if( buffer.size()==0 ){
					become( IDLE );
				}
				else{
					//prendi prossimo cliente, cioe' il piu' vecchio, dalla coda
					Cliente pc=buffer.removeFirst();
					osservatore.uscitaCoda( pc );
					tempoServizio = tempoServizio();					
					send( departure, ora+tempoServizio );
				}						
			}
		}//switch
	}//handler
	
}//Stazione